package frontend.parser;

import frontend.cehandler.compilationerrors.CEType;
import exceptions.ExpException;
import exceptions.ParseException;
import exceptions.PreconditionsException;
import exceptions.ReachEndException;
import frontend.cehandler.CEHandler;
import frontend.lexer.Lexer;
import frontend.lexer.token.Token;
import frontend.lexer.token.TokenType;
import frontend.parser.node.*;
import frontend.parser.node.decl.*;
import frontend.parser.node.expnode.Number;
import frontend.parser.node.expnode.*;
import frontend.parser.node.expnode.binaryexpnodes.*;
import frontend.parser.node.stmt.Block;
import frontend.parser.node.stmt.BlockItem;
import frontend.parser.node.stmt.ForStmt;
import frontend.parser.node.stmt.Stmt;
import utils.funcinterfaces.ThrowingSupplier;

import java.io.PrintWriter;
import java.util.Arrays;

public class Parser {
    final Lexer lexer;
    final PrintWriter printWriter;
    final PrintWriter debugWriter;
    final CEHandler ceHandler;
    private final ParserSupporter supporter;
    private CompUnit compUnit;
    public Parser(Lexer lexer, PrintWriter printWriter, PrintWriter debugWriter, CEHandler ceHandler) {
        this.lexer = lexer;
        this.printWriter = printWriter;
        this.debugWriter = debugWriter;
        this.ceHandler = ceHandler;
        this.supporter = new ParserSupporter(this);
    }
    public CompUnit analyse() {
        return (compUnit = parseCompUnit());
    }

    /* 根节点TokenNode判断与转换 */
    private boolean isTokenType(TokenType tokenType) {
        Token token = supporter.now();
        if (token == null) return false;
        return token.getTokenType() == tokenType;
    }
    private boolean isTokenType(int n, TokenType tokenType) {
        Token token = supporter.next(n);
        if (token == null) return false;
        return token.getTokenType() == tokenType;
    }
    private boolean isTokenType(TokenType... tokenTypes) {
        Token token = supporter.now();
        if (token == null) return false;
        for (TokenType tokenType: tokenTypes) {
            if (token.getTokenType() == tokenType) {
                return true;
            }
        }
        return false;
    }
    private boolean isTokenType(int n, TokenType... tokenTypes) {
        Token token = supporter.next(n);
        if (token == null) return false;
        for (TokenType tokenType: tokenTypes) {
            if (token.getTokenType() == tokenType) {
                return true;
            }
        }
        return false;
    }
    private TokenNode toTokenNode(TokenType tokenType) throws ParseException {
        Token token = supporter.now();
        if (token == null) {
            throw new ReachEndException();
        }
        if (token.getTokenType() == tokenType) {
            supporter.push();
            supporter.printTokenNode(token);
            return new TokenNode(token);
        }
        else {
            throw new ParseException();
        }
    }
    private TokenNode toTokenNode(TokenType... tokenTypes) throws ParseException {
        Token token = supporter.now();
        if (token == null) {
            throw new ReachEndException();
        }
        for (TokenType tokenType: tokenTypes) {
            if (token.getTokenType() == tokenType) {
                supporter.push();
                supporter.printTokenNode(token);
                return new TokenNode(token);
            }
        }
        throw new ParseException();
    }
    private TokenNode safeToTokenNode(TokenType tokenType) {
        Token token = supporter.now();
        if (token == null) {
            return null;
        }
        if (token.getTokenType() == tokenType) {
            supporter.push();
            supporter.printTokenNode(token);
            return new TokenNode(token);
        }
        else {
            return null;
        }
    }
    private TokenNode safeToTokenNode(TokenType... tokenTypes) {
        Token token = supporter.now();
        if (token == null) {
            return null;
        }
        for (TokenType tokenType: tokenTypes) {
            if (token.getTokenType() == tokenType) {
                supporter.push();
                supporter.printTokenNode(token);
                return new TokenNode(token);
            }
        }
        return null;
    }
    private TokenNode safeToNotNullTokenNode(TokenType tokenType) {
        TokenNode tokenNode = safeToTokenNode(tokenType);
        if (tokenNode == null) {
            throw new PreconditionsException(String.format("safeToNotNullTokenNode: %s", tokenType));
        }
        return tokenNode;
    }
    private TokenNode safeToNotNullTokenNode(TokenType... tokenTypes) {
        TokenNode tokenNode = safeToTokenNode(tokenTypes);
        if (tokenNode == null) {
            throw new PreconditionsException(String.format("safeToNotNullTokenNode: %s", Arrays.toString(tokenTypes)));
        }
        return tokenNode;
    }
    private String missingErrorMessage(String missingContent) {
        return String.format("expected \"%s\" after \"%s\"", missingContent, supporter.next(-1).getTokenString());
    }
    private TokenNode safeHandleMissingTokenNode(TokenType tokenType, CEType errorType, String expected, Node parent) {
        TokenNode tokenNode;
        if ((tokenNode = safeToTokenNode(tokenType)) == null) {
            Token token = new Token(tokenType, expected, 0, null, 0, 0);
            tokenNode = new TokenNode(token);
            supporter.error(errorType, missingErrorMessage(expected), supporter.next(-1), parent);
        }
        return tokenNode;
    }


    /* skip跳读方法 */
    /** 前置条件：无
     * <br/>
     * 后置条件：输出当前Token词法分析结果，跳过当前Token */
    private void skipToken() {
        if (supporter.hasNow()) {
            supporter.printTokenNode(supporter.now());
            supporter.push();
        }
    }
    /** 前置条件：读过(
     * <br/>
     * 后置条件：读过)||读到;{}||end
     * <br/>
     * <p>
     * 定义：
     * <br/>
     * 读过-在now（不含）之前存在该Token
     * <br/>
     * 读到-now恰好为该Token
     * </p> */
    private void skipRParent(boolean skipSemicnInParent) {
        skipToken();
        while (supporter.hasNow()) {
            if (isTokenType(TokenType.RPARENT)) {
                skipToken();
                return;
            }
            else if (!skipSemicnInParent && isTokenType(TokenType.SEMICN)) {
                return;
            }
            else if (isTokenType(TokenType.LBRACE, TokenType.RBRACE)) {
                return;
            }
            skipToken();
        }
    }
    /** 前置条件：进入语句且未读过语句块
     * <br/>
     * 后置条件：读过语句块||读过;||读到}||end */
    private void skipStmt() {
        skipToken();
        int layers = 0;
        while (supporter.hasNow()) {
            if (isTokenType(TokenType.LBRACE)) {
                layers++;
            }
            else if (isTokenType(TokenType.RBRACE)) {
                layers--;
                if (layers == 0) {
                    skipToken();
                    return;
                }
                else if (layers < 0) {
                    return;
                }
            }
            else if (isTokenType(TokenType.SEMICN)) {
                if (layers == 0) {
                    skipToken();
                    return;
                }
            }
            skipToken();
        }
    }
    /** 前置条件：进入表达式
     * <br/>
     * 后置条件：读过;||读到{}||end */
    private void skipExp() {
        skipToken();
        while (supporter.hasNow()) {
            if (isTokenType(TokenType.SEMICN)) {
                skipToken();
                return;
            }
            else if (isTokenType(TokenType.LBRACE, TokenType.RBRACE)) {
                return;
            }
            skipToken();
        }
    }
    /** 前置条件：无
     * <br/>
     * 后置条件：读到;||end */
    private void skipBeforeSemicn() {
        skipToken();
        while (supporter.hasNow()) {
            if (isTokenType(TokenType.SEMICN)) {
                return;
            }
            skipToken();
        }
    }


    /* 表达式级Node的parse方法 */
    private boolean isExp() {
        return isUnaryOp() || isPrimaryExp() || isTokenType(TokenType.IDENFR);
    }
    /** 前置条件：无 */
    private Exp parseExp() throws ExpException {
        Exp exp = new Exp();
        exp.addAddExp(parseAddExp());
        supporter.printNode("Exp");
        return exp;
    }
    /** 前置条件：无 */
    private Cond parseCond() throws ExpException {
        Cond cond = new Cond();
        cond.addLOrExp(parseLOrExp());
        supporter.printNode("Cond");
        return cond;
    }
    /** 前置条件：isTokenType(TokenType.IDENFR) */
    private LVal parseLVal() throws ExpException {
        LVal lVal = new LVal();
        lVal.addIdentTokenNode(safeToNotNullTokenNode(TokenType.IDENFR));
        for (int times = 0; times < 2 && isTokenType(TokenType.LBRACK); times++) {
            lVal.add(safeToNotNullTokenNode(TokenType.LBRACK));
            lVal.addDimIndexExp(parseExp());
            lVal.add(safeHandleMissingTokenNode(TokenType.RBRACK, CEType.k, "]", lVal));
        }
        supporter.printNode("LVal");
        return lVal;
    }
    /** 前置条件：isTokenType(TokenType.INTCON) */
    private Number parseNumber() {
        Number number = new Number();
        number.addIntConstTokenNode(safeToNotNullTokenNode(TokenType.INTCON)); // 前置条件
        supporter.printNode("Number");
        return number;
    }
    /** 前置条件：无 */
    private FuncRParams parseFuncRParams() throws ExpException {
        FuncRParams funcRParams = new FuncRParams();
        funcRParams.addExp(parseExp());
        while (isTokenType(TokenType.COMMA)) {
            funcRParams.add(safeToNotNullTokenNode(TokenType.COMMA));
            funcRParams.addExp(parseExp());
        }
        supporter.printNode("FuncRParams");
        return funcRParams;
    }
    private boolean isPrimaryExp() {
        return isTokenType(TokenType.LPARENT) || isTokenType(TokenType.IDENFR) && !isTokenType(1, TokenType.LPARENT) || isTokenType(TokenType.INTCON);
    }
    /** 前置条件：isPrimaryExp() */
    private PrimaryExp parsePrimaryExp() throws ExpException {
        PrimaryExp primaryExp = new PrimaryExp();
        if (isTokenType(TokenType.LPARENT)) {
            primaryExp.add(safeToNotNullTokenNode(TokenType.LPARENT));
            primaryExp.addExp(parseExp());
            primaryExp.add(safeHandleMissingTokenNode(TokenType.RPARENT, CEType.j, ")", primaryExp));
        }
        else if (isTokenType(TokenType.IDENFR)) {
            primaryExp.addLVal(parseLVal());
        }
        else if (isTokenType(TokenType.INTCON)) {
            primaryExp.addNumber(parseNumber());
        }
        else {
            throw new PreconditionsException("parsePrimaryExp");
        }
        supporter.printNode("PrimaryExp");
        return primaryExp;
    }
    private boolean isUnaryOp() {
        return isTokenType(TokenType.PLUS, TokenType.MINU, TokenType.NOT);
    }
    /** 前置条件：isUnaryOp() */
    private UnaryOp parseUnaryOp() {
        UnaryOp unaryOp = new UnaryOp();
        unaryOp.addOpTokenNode(safeToNotNullTokenNode(TokenType.PLUS, TokenType.MINU, TokenType.NOT)); // 需isSureUnaryOp()
        supporter.printNode("UnaryOp");
        return unaryOp;
    }
    /** 前置条件：无 */
    private UnaryExp parseUnaryExp() throws ExpException {
        UnaryExp unaryExp = new UnaryExp();

        int times = 1;
        while (isUnaryOp()) {
            unaryExp.addUnaryOp(parseUnaryOp());
            times++;
        }
        unaryExp.reverseUnaryOp(); // 逆序UnaryOp，使其符合一般执行顺序

        if (isPrimaryExp()) {
            unaryExp.addPrimaryExp(parsePrimaryExp());
        }
        else if (isTokenType(TokenType.IDENFR) && isTokenType(1, TokenType.LPARENT)) {
            unaryExp.addIdentTokenNode(safeToNotNullTokenNode(TokenType.IDENFR));
            unaryExp.add(safeToNotNullTokenNode(TokenType.LPARENT));
            if (isExp()) {
                unaryExp.addFuncRParams(parseFuncRParams());
            }
            unaryExp.add(safeHandleMissingTokenNode(TokenType.RPARENT, CEType.j, ")", unaryExp));
        }
        else {
            throw new ExpException();
        }

        for (int i = 0; i < times; i++) {
            supporter.printNode("UnaryExp");
        }

        return unaryExp;
    }

    private <T extends BinaryExpNode<C>, C extends Node> T parseBinaryExpNode (
            T binaryExpNode,
            ThrowingSupplier<C, ExpException> parseChildExp
    ) throws ExpException {
        binaryExpNode.addHeadChildExp(parseChildExp.get());
        supporter.printNode(binaryExpNode.getClass().getSimpleName());
        TokenNode tokenNode;
        while ((tokenNode = safeToTokenNode(binaryExpNode.getAllowedOperators())) != null) {
            binaryExpNode.addOperation(tokenNode.getTokenType(), parseChildExp.get());
            supporter.printNode(binaryExpNode.getClass().getSimpleName());
        }
        return binaryExpNode;
    }
    private MulExp parseMulExp() throws ExpException {
        return parseBinaryExpNode(new MulExp(), this::parseUnaryExp);
    }
    private AddExp parseAddExp() throws ExpException {
        return parseBinaryExpNode(new AddExp(), this::parseMulExp);
    }
    private RelExp parseRelExp() throws ExpException {
        return parseBinaryExpNode(new RelExp(), this::parseAddExp);
    }
    private EqExp parseEqExp() throws ExpException {
        return parseBinaryExpNode(new EqExp(), this::parseRelExp);
    }
    private LAndExp parseLAndExp() throws ExpException {
        return parseBinaryExpNode(new LAndExp(), this::parseEqExp);
    }
    private LOrExp parseLOrExp() throws ExpException {
        return parseBinaryExpNode(new LOrExp(), this::parseLAndExp);
    }


    /* 语句级Node的parse方法 */
    private boolean isStmt() {
        return isExp() || isTokenType(TokenType.IFTK, TokenType.FORTK, TokenType.BREAKTK, TokenType.CONTINUETK, TokenType.RETURNTK, TokenType.PRINTFTK, TokenType.LBRACE, TokenType.SEMICN);
    }
    /** 前置条件：isStmt()
     * <br/>
     * 后置条件：如果报错返回null并略过 */
    private Stmt parseStmt() {
        Stmt stmt = new Stmt();
        Stmt tempStmt1, tempStmt2;
        int status = 0;
        if (isTokenType(TokenType.IFTK)) {
            try {
                Stmt.IfInf ifInf = (Stmt.IfInf) stmt.setType(Stmt.StmtType.IF);

                ifInf.add(safeToNotNullTokenNode(TokenType.IFTK));
                ifInf.add(toTokenNode(TokenType.LPARENT));
                status = 1;
                ifInf.addCond(parseCond());
                ifInf.add(safeHandleMissingTokenNode(TokenType.RPARENT, CEType.j, ")", stmt));
                ifInf.addIfStmt(tempStmt1 = parseStmt());
                status = 2;
                if (isTokenType(TokenType.ELSETK)) {
                    ifInf.addElseTokenNode(safeToNotNullTokenNode(TokenType.ELSETK));
                    ifInf.addElseStmt(tempStmt2 = parseStmt()); if (tempStmt2 == null) throw new ParseException();
                }
                if (tempStmt1 == null) throw new ParseException();
            } catch (ParseException e) {
                switch (status) {
                case 0:
                    skipStmt();
                    break;
                case 1:
                    skipRParent(false);
                    skipStmt();
                    if (!isTokenType(TokenType.ELSETK)) break;
                    skipStmt();
                    break;
                }
                supporter.error(CEType.op, "Syntax error in ifStmt", stmt);
                return null;
            }
        }
        else if (isTokenType(TokenType.FORTK)) {
            try {
                Stmt.ForInf forInf = (Stmt.ForInf) stmt.setType(Stmt.StmtType.FOR);

                forInf.add(safeToNotNullTokenNode(TokenType.FORTK));
                forInf.add(toTokenNode(TokenType.LPARENT));
                status = 1;
                if (isTokenType(TokenType.IDENFR)) {
                    forInf.addForStmt1(parseForStmt());
                }
                forInf.add(toTokenNode(TokenType.SEMICN));
                if (isExp()) {
                    forInf.addCond(parseCond());
                }
                forInf.add(toTokenNode(TokenType.SEMICN));
                if (isTokenType(TokenType.IDENFR)) {
                    forInf.addForStmt2(parseForStmt());
                }
                forInf.add(safeHandleMissingTokenNode(TokenType.RPARENT, CEType.j, ")", stmt));
                status = 2;
                forInf.addStmt(tempStmt1 = parseStmt()); if (tempStmt1 == null) throw new ParseException();
            } catch (ParseException e) {
                switch (status) {
                case 0:
                    skipStmt();
                    break;
                case 1:
                    skipRParent(true);
                    skipStmt();
                    break;
                }
                e.printStackTrace();
                supporter.error(CEType.op, "Syntax error in forStmt", stmt);
                return null;
            }
        }
        else if (isTokenType(TokenType.BREAKTK)) {
            Stmt.BreakInf breakInf = (Stmt.BreakInf) stmt.setType(Stmt.StmtType.BREAK);

            breakInf.addBreakTokenNode(safeToNotNullTokenNode(TokenType.BREAKTK));
            breakInf.add(safeHandleMissingTokenNode(TokenType.SEMICN, CEType.i, ";", stmt));
        }
        else if (isTokenType(TokenType.CONTINUETK)) {
            Stmt.ContinueInf continueInf = (Stmt.ContinueInf) stmt.setType(Stmt.StmtType.CONTINUE);

            continueInf.addContinueTokenNode(safeToNotNullTokenNode(TokenType.CONTINUETK));
            continueInf.add(safeHandleMissingTokenNode(TokenType.SEMICN, CEType.i, ";", stmt));
        }
        else if (isTokenType(TokenType.RETURNTK)) {
            try {
                Stmt.ReturnInf returnInf = (Stmt.ReturnInf) stmt.setType(Stmt.StmtType.RETURN);

                returnInf.addReturnTokenNode(safeToNotNullTokenNode(TokenType.RETURNTK));
                if (isExp()) {
                    returnInf.addExp(parseExp());
                }
                returnInf.add(safeHandleMissingTokenNode(TokenType.SEMICN, CEType.i, ";", stmt));
            } catch (ParseException e) {
                skipExp();
                supporter.error(CEType.op, "Syntax error in returnStmt", stmt);
                return null;
            }
        }
        else if (isTokenType(TokenType.PRINTFTK)) {
            try {
                Stmt.PrintfInf printfInf = (Stmt.PrintfInf) stmt.setType(Stmt.StmtType.PRINTF);
                
                printfInf.add(safeToNotNullTokenNode(TokenType.PRINTFTK));
                printfInf.add(toTokenNode(TokenType.LPARENT));
                status = 1;
                printfInf.addStrConTokenNode(toTokenNode(TokenType.STRCON));
                while (isTokenType(TokenType.COMMA)) {
                    printfInf.add(safeToNotNullTokenNode(TokenType.COMMA));
                    printfInf.addExp(parseExp());
                }
                printfInf.add(safeHandleMissingTokenNode(TokenType.RPARENT, CEType.j, ")", stmt));
                printfInf.add(safeHandleMissingTokenNode(TokenType.SEMICN, CEType.i, ";", stmt));
            } catch (ParseException e) {
                switch (status) {
                    case 0:
                        skipStmt();
                        break;
                    case 1:
                        skipRParent(true);
                        skipExp();
                        break;
                }
                supporter.error(CEType.op, "Syntax error in printfStmt", stmt);
                return null;
            }
        }
        else if (isTokenType(TokenType.LBRACE)) {
            Stmt.BlockInf blockInf = (Stmt.BlockInf) stmt.setType(Stmt.StmtType.BLOCK);

            blockInf.addBlock(parseBlock());
        }
        else if (isTokenType(TokenType.SEMICN)) {
            Stmt.SemicnInf semicnInf = (Stmt.SemicnInf) stmt.setType(Stmt.StmtType.SEMICN);

            semicnInf.add(safeToNotNullTokenNode(TokenType.SEMICN));
        }
        else {
            try {
                handleExpOrLValInStmt(stmt);
                
            } catch (ParseException e) {
                skipExp();
                return null;
            }
        }
        supporter.printNode("Stmt");
        return stmt;
    }
    private void handleExpOrLValInStmt(Stmt stmt) throws ParseException {
        if (!isTokenType(TokenType.IDENFR)) {
            handleExpInStmt(stmt);
            return;
        }
        if (isTokenType(1, TokenType.ASSIGN)) {
            handleLValInStmt(stmt, null);
            return;
        }
        if (!isTokenType(1, TokenType.LBRACK)) {
            handleExpInStmt(stmt);
            return;
        }

        supporter.startTrying(); // 假读
        LVal lVal = null;
        boolean passingParseLVal = true;
        try {
            lVal = parseLVal();
        } catch (ExpException e) { passingParseLVal = false; }
        if (passingParseLVal && isTokenType(TokenType.ASSIGN)) {
            supporter.endTrying(true); // 假读变真读
            handleLValInStmt(stmt, lVal);
        }
        else {
            supporter.endTrying(false); // 假读回溯
            handleExpInStmt(stmt);
        }
    }
    private void handleExpInStmt(Stmt stmt) throws ExpException {
        try {
            Stmt.ExpInf expInf = (Stmt.ExpInf) stmt.setType(Stmt.StmtType.EXP);

            expInf.addExp(parseExp());
            stmt.add(safeHandleMissingTokenNode(TokenType.SEMICN, CEType.i, ";", stmt));
        } catch (ExpException e) {
            supporter.error(CEType.op, "Syntax error in ExpStmt", stmt);
            throw e;
        }
    }
    /** 前置条件：isTokenType(TokenType.IDENFR) when lVal is null, else isTokenType(TokenType.ASSIGN) */
    private void handleLValInStmt(Stmt stmt, LVal lVal) throws ParseException {
        try {
            if (lVal == null) {
                lVal = parseLVal();
            }
            
            if (isTokenType(1, TokenType.GETINTTK)) {
                Stmt.GetintInf getintInf = (Stmt.GetintInf) stmt.setType(Stmt.StmtType.GETINT);
                
                getintInf.addLVal(lVal);
                getintInf.add(toTokenNode(TokenType.ASSIGN));
                getintInf.add(safeToNotNullTokenNode(TokenType.GETINTTK));
                getintInf.add(toTokenNode(TokenType.LPARENT));
                getintInf.add(safeHandleMissingTokenNode(TokenType.RPARENT, CEType.j, ")", stmt));
                getintInf.add(safeHandleMissingTokenNode(TokenType.SEMICN, CEType.i, ";", stmt));
            } else {
                Stmt.AssignInf assignInf = (Stmt.AssignInf) stmt.setType(Stmt.StmtType.ASIGN);

                assignInf.addLVal(lVal);
                assignInf.add(toTokenNode(TokenType.ASSIGN));
                assignInf.addExp(parseExp());
                assignInf.add(safeHandleMissingTokenNode(TokenType.SEMICN, CEType.i, ";", stmt));
            }
            
        } catch (ParseException e) {
            supporter.error(CEType.op, "Syntax error in LValStmt", stmt);
            throw e;
        }
    }
    /** 前置条件：isTokenType(TokenType.IDENFR) */
    private ForStmt parseForStmt() throws ParseException {
        ForStmt forStmt = new ForStmt();
        forStmt.addLVal(parseLVal()); // 前置条件 isToken IDENFR
        forStmt.add(toTokenNode(TokenType.ASSIGN));
        forStmt.addExp(parseExp());
        supporter.printNode("ForStmt");
        return forStmt;
    }
    /** 前置条件：isTokenType(TokenType.LBRACE) */
    private Block parseBlock() {
        Block block = new Block();
        block.add(safeToNotNullTokenNode(TokenType.LBRACE)); // 前置条件：LBRACE
        while(supporter.hasNow() && !isTokenType(TokenType.RBRACE)) {
            if (isBlockItemWithSkip(CEType.op, "illegal token in block", block)) {
                BlockItem blockItem = parseBlockItem(); if (blockItem != null) block.addBlockItem(blockItem);
            }
        }
        block.addEndRBrace(safeHandleMissingTokenNode(TokenType.RBRACE, CEType.op, "}", block));
        supporter.printNode("Block");
        return block;
    }
    private boolean isBlockItemWithSkip(CEType ceType, String message, Node causedNode) {
        boolean ret = isBlockItem();
        if (!isBlockItem()) {
            supporter.error(ceType, message, causedNode);
            skipExp();
        }
        return ret;
    }
    private boolean isBlockItem() {
        return isDecl() || isStmt();
    }
    /** 前置条件：isBlockItem()
     * <br/>
     * 后置条件：报错并跳过返回null */
    private BlockItem parseBlockItem() {
        BlockItem blockItem = new BlockItem();
        if (isDecl()) {
            Decl decl = parseDecl(); if (decl == null) return null;
            blockItem.addDecl(decl);
        }
        else if (isStmt()) {
            Stmt stmt = parseStmt(); if (stmt == null) return null;
            blockItem.addStmt(stmt);
        }
        else {
            throw new PreconditionsException("parseBlockItem");
        }
        return blockItem;
    }
    private boolean isDecl() {
        return isConstDecl() || isVarDecl();
    }
    /** 前置条件：isDecl() */
    private Decl parseDecl() {
        Decl decl = new Decl();
        try {
            if (isTokenType(TokenType.CONSTTK)) {
                decl.addConstDecl(parseConstDecl());
            }
            else if (isTokenType(TokenType.INTTK)) {
                decl.addVarDecl(parseVarDecl());
            }
            else {
                throw new PreconditionsException("parseDecl");
            }
        } catch (ParseException e) {
            supporter.error(CEType.op, "Syntax error in Decl", decl);
            return null;
        }
        return decl;
    }
    /** 前置条件：isTokenNode(TokenType.INTTK) */
    private BType parseBType() {
        BType bType = new BType();
        bType.add(safeToNotNullTokenNode(TokenType.INTTK));
        return bType;
    }
    private BType parseBTypeThrowing() throws ParseException {
        BType bType = new BType();
        bType.add(toTokenNode(TokenType.INTTK));
        return bType;
    }
    private boolean isConstDecl() {
        return isTokenType(TokenType.CONSTTK) && isTokenType(1, TokenType.INTTK) && isTokenType(2, TokenType.IDENFR) && !isTokenType(3, TokenType.LPARENT);
    }
    /** 前置条件：isConstDecl()
     * <br/>
     * 后置条件：报错并跳过 */
    private ConstDecl parseConstDecl() throws ParseException {
        ConstDecl constDecl = new ConstDecl();
        constDecl.add(safeToNotNullTokenNode(TokenType.CONSTTK)); // 前置条件 const int <idenfr> not'('
        constDecl.add(parseBType());
        while (true) {
            constDecl.addConstDef(parseConstDef());
            if (isTokenType(TokenType.COMMA)) {
                constDecl.add(safeToNotNullTokenNode(TokenType.COMMA));
            }
            else break;
        }
        constDecl.add(safeHandleMissingTokenNode(TokenType.SEMICN, CEType.i, ";", constDecl));
        supporter.printNode("ConstDecl");
        return constDecl;
    }
    /** 前置条件：无
     * <br/>
     * 后置条件：报错并跳过 */
    private ConstDef parseConstDef() throws ParseException {
        ConstDef constDef = new ConstDef();
        constDef.addIdentTokenNode(toTokenNode(TokenType.IDENFR));
        for (int times = 0; times < 2 && isTokenType(TokenType.LBRACK); times++) {
            constDef.add(safeToNotNullTokenNode(TokenType.LBRACK));
            constDef.addDimLenConstExp(parseConstExp());
            constDef.add(safeHandleMissingTokenNode(TokenType.RBRACK, CEType.k, "]", constDef));
        }
        constDef.add(toTokenNode(TokenType.ASSIGN));
        constDef.addConstInitVal(parseConstInitVal());
        supporter.printNode("ConstDef");
        return constDef;
    }
    /** 前置条件：无
     * <br/>
     * 后置条件：报错并跳过 */
    private ConstInitVal parseConstInitVal() throws ParseException {
        ConstInitVal constInitVal = new ConstInitVal();
        try {
            if (!isTokenType(TokenType.LBRACE)) { // 0维
                constInitVal.setDimension(0);
                constInitVal.addValExp(parseConstExp());
                supporter.printNode("ConstInitVal");
            }
            else if (!isTokenType(1, TokenType.LBRACE)) { // 1维
                constInitVal.setDimension(1);
                constInitVal.add(safeToNotNullTokenNode(TokenType.LBRACE));
                while (true) {
                    constInitVal.addValExp(parseConstExp());
                    supporter.printNode("ConstInitVal");
                    if (isTokenType(TokenType.COMMA)) {
                        constInitVal.add(safeToNotNullTokenNode(TokenType.COMMA));
                    }
                    else break;
                }
                constInitVal.add(safeHandleMissingTokenNode(TokenType.RBRACE, CEType.op, "}", constInitVal));
                supporter.printNode("ConstInitVal");
            }
            else { // 二维
                constInitVal.setDimension(2);
                constInitVal.add(safeToNotNullTokenNode(TokenType.LBRACE));
                while (true) {
                    constInitVal.add(toTokenNode(TokenType.LBRACE));
                    constInitVal.dim2NewArray();
                    while (true) {
                        constInitVal.addValExp(parseConstExp());
                        supporter.printNode("ConstInitVal");
                        if (isTokenType(TokenType.COMMA)) {
                            constInitVal.add(safeToNotNullTokenNode(TokenType.COMMA));
                        }
                        else break;
                    }
                    constInitVal.add(safeHandleMissingTokenNode(TokenType.RBRACE, CEType.op, "}", constInitVal));
                    supporter.printNode("ConstInitVal");
                    if (isTokenType(TokenType.COMMA)) {
                        constInitVal.add(safeToNotNullTokenNode(TokenType.COMMA));
                    }
                    else break;
                }
                constInitVal.add(safeHandleMissingTokenNode(TokenType.RBRACE, CEType.op, "}", constInitVal));
                supporter.printNode("ConstInitVal");
            }
        } catch (ParseException e) {
            supporter.error(CEType.op, "Syntax error in ConstInitVal", constInitVal);
            skipBeforeSemicn();
            throw new ParseException();
        }
        return constInitVal;
    }
    /*
    // 旧版parseConstInitVal
    private ConstInitVal parseConstInitVal() throws ReachEndException {
        ConstInitVal constInitVal = new ConstInitVal();
        if (!isTokenType(TokenType.LBRACE)) {
            constInitVal.addValExp(parseConstExp());
        }
        else {
            constInitVal.add(toTokenNode(TokenType.LBRACE));
            if (!isTokenType(TokenType.RBRACE)) {
                constInitVal.add(parseConstInitVal());
                while (isTokenType(TokenType.COMMA)) {
                    constInitVal.add(toTokenNode(TokenType.COMMA));
                    constInitVal.add(parseConstInitVal());
                }
            }
            constInitVal.add(toTokenNode(TokenType.RBRACE));
        }
        supporter.printNode("ConstInitVal");
        return constInitVal;
    }
    */
    /** 前置条件：无 */
    private ConstExp parseConstExp() throws ExpException {
        ConstExp constExp = new ConstExp();
        constExp.addAddExp(parseAddExp());
        supporter.printNode("ConstExp");
        return constExp;
    }
    private boolean isVarDecl() {
        return isTokenType(TokenType.INTTK) && isTokenType(1, TokenType.IDENFR) && !isTokenType(2, TokenType.LPARENT);
    }
    /** 前置条件：isVarDecl()
     * <br/>
     * 后置条件：报错并跳过 */
    private VarDecl parseVarDecl() throws ParseException {
        VarDecl varDecl = new VarDecl();
        varDecl.add(parseBType());
        while (true) {
            varDecl.addVarDef(parseVarDef());
            if (isTokenType(TokenType.COMMA)) {
                varDecl.add(safeToNotNullTokenNode(TokenType.COMMA));
            }
            else break;
        }
        varDecl.add(safeHandleMissingTokenNode(TokenType.SEMICN, CEType.i, ";", varDecl));
        supporter.printNode("VarDecl");
        return varDecl;
    }
    /** 前置条件：无
     * <br/>
     * 后置条件：报错并跳过 */
    private VarDef parseVarDef() throws ParseException {
        VarDef varDef = new VarDef();
        varDef.addIdentTokenNode(toTokenNode(TokenType.IDENFR));
        for (int times = 0; times < 2 && isTokenType(TokenType.LBRACK); times++) {
            varDef.add(safeToNotNullTokenNode(TokenType.LBRACK));
            varDef.addDimLenConstExp(parseConstExp());
            varDef.add(safeHandleMissingTokenNode(TokenType.RBRACK, CEType.k, "]", varDef));
        }
        if (isTokenType(TokenType.ASSIGN)) {
            varDef.add(safeToNotNullTokenNode(TokenType.ASSIGN));
            varDef.addInitVal(parseInitVal());
        }
        supporter.printNode("VarDef");
        return varDef;
    }
    /** 前置条件：无
     * <br/>
     * 后置条件：报错并跳过 */
    private InitVal parseInitVal() throws ParseException {
        InitVal initVal = new InitVal();
        try {
            if (!isTokenType(TokenType.LBRACE)) { // 0维
                initVal.setDimension(0);
                initVal.addValExp(parseExp());
                supporter.printNode("InitVal");
            }
            else if (!isTokenType(1, TokenType.LBRACE)) { // 1维
                initVal.setDimension(1);
                initVal.add(safeToNotNullTokenNode(TokenType.LBRACE));
                while (true) {
                    initVal.addValExp(parseExp());
                    supporter.printNode("InitVal");
                    if (isTokenType(TokenType.COMMA)) {
                        initVal.add(safeToNotNullTokenNode(TokenType.COMMA));
                    }
                    else break;
                }
                initVal.add(safeHandleMissingTokenNode(TokenType.RBRACE, CEType.op, "}", initVal));
                supporter.printNode("InitVal");
            }
            else { // 二维
                initVal.setDimension(2);
                initVal.add(safeToNotNullTokenNode(TokenType.LBRACE));
                while (true) {
                    initVal.add(toTokenNode(TokenType.LBRACE));
                    initVal.dim2NewArray();
                    while (true) {
                        initVal.addValExp(parseExp());
                        supporter.printNode("InitVal");
                        if (isTokenType(TokenType.COMMA)) {
                            initVal.add(safeToNotNullTokenNode(TokenType.COMMA));
                        }
                        else break;
                    }
                    initVal.add(safeHandleMissingTokenNode(TokenType.RBRACE, CEType.op, "}", initVal));
                    supporter.printNode("InitVal");
                    if (isTokenType(TokenType.COMMA)) {
                        initVal.add(safeToNotNullTokenNode(TokenType.COMMA));
                    }
                    else break;
                }
                initVal.add(safeHandleMissingTokenNode(TokenType.RBRACE, CEType.op, "}", initVal));
                supporter.printNode("InitVal");
            }
        } catch (ParseException e) {
            supporter.error(CEType.op, "Syntax error in InitVal", initVal);
            skipBeforeSemicn();
            throw new ParseException();
        }
        return initVal;
    }
    /*
    // 旧版2 麻烦的循环
    private InitVal parseInitVal() {
        InitVal initVal = new InitVal();
        if (!isTokenType(TokenType.LBRACE)) { // 0维
            initVal.addValExp(parseExp());
            supporter.printNode("InitVal");
        }
        else if (!isTokenType(1, TokenType.LBRACE)) { // 1维
            initVal.add(safeToNotNullTokenNode(TokenType.LBRACE));
            initVal.addValExp(parseExp());
            supporter.printNode("InitVal");
            while (isTokenType(TokenType.COMMA)) {
                initVal.add(safeToNotNullTokenNode(TokenType.COMMA));
                initVal.addValExp(parseExp());
                supporter.printNode("InitVal");
            }
            initVal.add(safeHandleMissingTokenNode(TokenType.RBRACE, CEType.op, "}", initVal));
            supporter.printNode("InitVal");
        }
        else {
            initVal.add(safeToNotNullTokenNode(TokenType.LBRACE));

            initVal.add(safeToNotNullTokenNode(TokenType.LBRACE));
            initVal.addValExp(parseExp());
            supporter.printNode("InitVal");
            while (isTokenType(TokenType.COMMA)) {
                initVal.add(safeToNotNullTokenNode(TokenType.COMMA));
                initVal.addValExp(parseExp());
                supporter.printNode("InitVal");
            }
            initVal.add(safeHandleMissingTokenNode(TokenType.RBRACE, CEType.op, "}", initVal));
            supporter.printNode("InitVal");

            while (isTokenType(TokenType.COMMA)) {
                initVal.add(safeToNotNullTokenNode(TokenType.COMMA));

                initVal.add(safeToNotNullTokenNode(TokenType.LBRACE));
                initVal.addValExp(parseExp());
                supporter.printNode("InitVal");
                while (isTokenType(TokenType.COMMA)) {
                    initVal.add(safeToNotNullTokenNode(TokenType.COMMA));
                    initVal.addValExp(parseExp());
                    supporter.printNode("InitVal");
                }
                initVal.add(safeHandleMissingTokenNode(TokenType.RBRACE, CEType.op, "}", initVal));
                supporter.printNode("InitVal");
            }
            initVal.add(safeHandleMissingTokenNode(TokenType.RBRACE, CEType.op, "}", initVal));
            supporter.printNode("InitVal");
        }
        return initVal;
    }
     */
    /*
    // 旧版parseInitVal()递归实现弃用
    private InitVal parseInitVal() throws ParseException {
        InitVal initVal = new InitVal();
        if (!isTokenType(TokenType.LBRACE)) {
            initVal.addValExp(parseExp());
        }
        else {
            initVal.add(safeToNotNullTokenNode(TokenType.LBRACE));
            if (!isTokenType(TokenType.RBRACE)) {
                initVal.add(parseInitVal());
                while (isTokenType(TokenType.COMMA)) {
                    initVal.add(safeToNotNullTokenNode(TokenType.COMMA));
                    initVal.add(parseInitVal());
                }
            }
            initVal.add(toTokenNode(TokenType.RBRACE));
        }
        supporter.printNode("InitVal");
        return initVal;
    }
     */


    /* 函数定义 */
    private boolean isFuncDef() {
        return isFuncType() && isTokenType(1, TokenType.IDENFR) && isTokenType(2, TokenType.LPARENT);
    }
    /** 前置条件：isFuncDef() */
    private FuncDef parseFuncDef() {
        FuncDef funcDef = new FuncDef();
        try {
            funcDef.addFuncType(parseFuncType());
            funcDef.addIdentTokenNode(safeToNotNullTokenNode(TokenType.IDENFR));
            funcDef.add(safeToNotNullTokenNode(TokenType.LPARENT));
            if (isFuncFParams()) {
                funcDef.addFuncFParams(parseFuncFParams());
            }
            funcDef.add(safeHandleMissingTokenNode(TokenType.RPARENT, CEType.j, ")", funcDef));
            funcDef.addBlock(parseBlock());
            supporter.printNode("FuncDef");
        } catch (ParseException e) {
            supporter.error(CEType.op, "Syntax error in FuncDef", funcDef);
            return null;
        }
        return funcDef;
    }
    private boolean isFuncType() {
        return isTokenType(TokenType.INTTK, TokenType.VOIDTK);
    }
    /** 前置条件：isFuncType() */
    private FuncType parseFuncType() {
        FuncType funcType = new FuncType();
        funcType.addFuncTypeTokenNode(safeToNotNullTokenNode(TokenType.INTTK, TokenType.VOIDTK));
        supporter.printNode("FuncType");
        return funcType;
    }
    private boolean isFuncFParams() {
        return isTokenType(TokenType.INTTK) && isTokenType(1, TokenType.IDENFR);
    }
    /** 前置条件：无 */
    private FuncFParams parseFuncFParams() throws ParseException {
        FuncFParams funcFParams = new FuncFParams();
        funcFParams.addFuncFParam(parseFuncFParam());
        while (isTokenType(TokenType.COMMA)) {
            funcFParams.add(safeToNotNullTokenNode(TokenType.COMMA));
            funcFParams.addFuncFParam(parseFuncFParam());
        }
        supporter.printNode("FuncFParams");
        return funcFParams;
    }
    /** 前置条件：无 */
    private FuncFParam parseFuncFParam() throws ParseException {
        FuncFParam funcFParam = new FuncFParam();
        funcFParam.add(parseBTypeThrowing());
        funcFParam.addIdentTokenNode(toTokenNode(TokenType.IDENFR));
        for (int times = 0; times < 2 && isTokenType(TokenType.LBRACK); times++) {
            funcFParam.add(safeToNotNullTokenNode(TokenType.LBRACK));
            if (times > 0) {
                funcFParam.addDimLenConstExp(parseConstExp());
            }
            funcFParam.addRbrackTokenNode(safeHandleMissingTokenNode(TokenType.RBRACK, CEType.k, "]", funcFParam));
        }
        supporter.printNode("FuncFParam");
        return funcFParam;
    }


    /* 根节点 */
    private CompUnit parseCompUnit() {
        CompUnit compUnit = new CompUnit();
        boolean mainFuncFlag = false;
        while (supporter.hasNow()) {
            if (isDecl()) {
                Decl decl = parseDecl();
                if (decl != null) compUnit.addDecl(decl);
            }
            else if (isFuncDef()) {
                FuncDef funcDef = parseFuncDef();
                if (funcDef != null) compUnit.addFuncDef(funcDef);
            }
            else if (isMainFuncDef()) {
                compUnit.addMainFuncDef(parseMainFuncDef());
                mainFuncFlag = true;
                break;
            }
            else {
                supporter.error(CEType.op, "illegal token in CompUnit", compUnit);
                skipExp();
            }
        }
        if (!mainFuncFlag) {
            supporter.error(CEType.op, "main function not found", compUnit);
            return compUnit;
        }
        supporter.printNode("CompUnit");
        if (supporter.hasNow()) {
            supporter.error(CEType.op, "there are still tokens after the main function ends", compUnit);
            while (supporter.hasNow()) {
                skipToken();
            }
        }
        return compUnit;
    }
    private boolean isMainFuncDef() {
        return isTokenType(TokenType.INTTK) &&
                isTokenType(1, TokenType.MAINTK) &&
                isTokenType(2, TokenType.LPARENT) &&
                isTokenType(3, TokenType.RPARENT) &&
                isTokenType(4, TokenType.LBRACE);
    }
    /** 前置条件：isMainFuncDef() */
    private MainFuncDef parseMainFuncDef() {
        MainFuncDef mainFuncDef = new MainFuncDef();
        mainFuncDef.add(safeToNotNullTokenNode(TokenType.INTTK));
        mainFuncDef.add(safeToNotNullTokenNode(TokenType.MAINTK));
        mainFuncDef.add(safeToNotNullTokenNode(TokenType.LPARENT));
        mainFuncDef.add(safeToNotNullTokenNode(TokenType.RPARENT));
        mainFuncDef.addBlock(parseBlock());
        supporter.printNode("MainFuncDef");
        return mainFuncDef;
    }

}
